package cn.sylinx.horm.model.optlock;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;

import cn.sylinx.horm.config.OrmConfigHolder;
import cn.sylinx.horm.model.anno.Version;
import cn.sylinx.horm.model.cache.ModelCacheUtil;
import cn.sylinx.horm.util.GLog;

public enum OptimisticLockWrapper {
    ;

    public static <T> OptimisticLockInsert parseOptimisticLockInsert(T t) {
        if (!OrmConfigHolder.isOptimisticLockEnable()) {
            // 乐观锁不可用
            return null;
        }
        if (t == null) {
            return null;
        }

        Field f = ModelCacheUtil.getVersionField(t.getClass());
        if (f == null) {
            // 没有乐观锁字段
            return null;
        }
        Number initVersionValue = getInitVersionValue(f.getType());
        if (initVersionValue == null) {
            return null;
        }
        OptimisticLockInsert oli = new OptimisticLockInsert();
        oli.setVersionField(f);
        oli.setVersionFieldAttr(f.getName());
        oli.setInitVersionValue(initVersionValue);
        return oli;
    }

    public static <T> OptimisticLockUpdate parseOptimisticLockUpdate(T t) {
        if (!OrmConfigHolder.isOptimisticLockEnable()) {
            // 乐观锁不可用
            return null;
        }
        if (t == null) {
            return null;
        }
        Field f = ModelCacheUtil.getVersionField(t.getClass());
        if (f == null) {
            // 没有乐观锁字段
            return null;
        }
        Number versionValue = null;
        try {
            f.setAccessible(true);
            versionValue = (Number) f.get(t);
        } catch (Exception e) {
            GLog.error("getVersionField error", e);
        }
        if (versionValue == null) {
            return null;
        }
        Number newVersionValue = getNewVersionValue(versionValue);
        if (newVersionValue == null) {
            return null;
        }
        OptimisticLockUpdate olu = new OptimisticLockUpdate();
        olu.setNewVersionValue(newVersionValue);
        olu.setOldVersionValue(versionValue);
        olu.setVersionField(f);
        olu.setVersionFieldAttr(f.getName());
        return olu;
    }

    private static Number getNewVersionValue(Number oldVersionValue) {
        // 判断字段类型
        Class<?> clz = oldVersionValue.getClass();
        if (clz == Version.VERSION_TYPE_INTEGER || clz == Version.VERSION_TYPE_INTEGER_PRIMARY) {
            return (Integer) oldVersionValue + 1;
        }
        if (clz == Version.VERSION_TYPE_LONG || clz == Version.VERSION_TYPE_LONG_PRIMARY) {
            return (Long) oldVersionValue + 1;
        }
        if (clz == Version.VERSION_TYPE_BIGINTEGER) {
            return ((BigInteger) oldVersionValue).add(new BigInteger("1"));
        }
        if (clz == Version.VERSION_TYPE_BIGDECIMAL) {
            return ((BigDecimal) oldVersionValue).add(new BigDecimal("1"));
        }
        return null;
    }

    private static Number getInitVersionValue(Class<?> clz) {
        // 判断字段类型
        if (clz == Version.VERSION_TYPE_INTEGER || clz == Version.VERSION_TYPE_INTEGER_PRIMARY) {
            return 1;
        }
        if (clz == Version.VERSION_TYPE_LONG || clz == Version.VERSION_TYPE_LONG_PRIMARY) {
            return 1L;
        }
        if (clz == Version.VERSION_TYPE_BIGINTEGER) {
            return new BigInteger("1");
        }
        if (clz == Version.VERSION_TYPE_BIGDECIMAL) {
            return new BigDecimal("1");
        }
        return null;
    }
}